package co.gov.medellin.ssti.sub.common;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class ConnectionFactory {
	// Produccion
	private static final String JDNI_DATASOURCE = "jdbc/ds_beneficios";

	private Connection conn;
	private DataSource ds;
	private PreparedStatement pstmt = null;

	/**
	 * 
	 * @return
	 * @throws SQLException
	 */
	public Connection getConnection() throws SQLException {
		conn = null;
		try {
			InitialContext initctx = new InitialContext();
			ds = (DataSource) initctx.lookup(JDNI_DATASOURCE);
			conn = ds.getConnection();
		} catch (NamingException e) {
			System.out.println("Error getting the connection: "
					+ e.getMessage());
		}

		return conn;
	} // End getConnection

	/**
	 * 
	 * @param con
	 * @throws SQLException
	 */
	public void closeConnection(Connection con) throws SQLException {
		if (con != null && !con.isClosed()) {
			if (pstmt != null) {
				pstmt.close();
			}
			con.close();
		}
	} // End closeConnection

	/**
	 * Metodo que busca la cantidad de ocurrencias de un caracter en una cadena
	 * 
	 * @param strToken
	 *            Cadena en que se buscaria el caracter strSearch
	 * @strSearch Caracter a buscar
	 * @return int con la cantidad de ocurrencias en una cadena
	 */
	public int getOcurrencesCount(String strToken, char strSearch) {
		int iStart = 0;
		int icontOcur = 0;
		while (strToken.indexOf(strSearch, iStart) != -1) {
			icontOcur++;
			iStart = strToken.indexOf(strSearch, iStart) + 1;
		}
		return icontOcur;
	}

	/**
	 * Valida que los parametros enviados a un SQL esten completos y correctos
	 * 
	 * @param String
	 *            strSql instruccion SQL
	 * @param parPrepar
	 *            arreglo con los parametros del SQL, si el SQL no lleva
	 *            parametros este valor seria null
	 * @return PreparedStatement, en caso que haya un problema con los
	 *         parametros se retornaria null
	 */
	private PreparedStatement getPstmtWithArguments(String strSql,
			String parPrepar[], Connection conn) throws SQLException {

		pstmt = conn.prepareStatement(strSql);
		if (parPrepar != null) {
			int iOcurrencesCount = getOcurrencesCount(strSql, '?');
			if (iOcurrencesCount != parPrepar.length) {
				System.err
						.println("Se tiene "
								+ iOcurrencesCount
								+ " ? en el SQL del PreparedStatement  para "
								+ parPrepar.length
								+ " parametros marcados. No se ejecuto la instruccion.");
			}
			for (int i = 0; i < parPrepar.length; i++) {
				pstmt.setString(i + 1, parPrepar[i]);
			}
		}

		return pstmt;
	}

	/**
	 * Metodo que ejecuta un comando SQL con instrucciones preparadas
	 * 
	 * @param strSql
	 *            Dml (Insert, update, delete) SQL
	 * @param parPrepar
	 *            arreglo que determinan los parametros marcados de la
	 *            instruccion preparada, su dimension debe ser igual a cuantos ?
	 *            halla en strSql si su valor es null, indica que el SQL no
	 *            tiene parametros
	 * @return cantidad de registros afectados
	 */
	public int execSql(String strSql, String parPrepar[], Connection conn)
			throws SQLException {
		pstmt = getPstmtWithArguments(strSql, parPrepar, conn);
		return pstmt.executeUpdate();
	}

	/**
	 * Metodo ejecuta una consulta realizada con instrucciones preparadas
	 * 
	 * @param strQuery
	 *            Consulta SQL
	 * @param parPrepar
	 *            arreglo que determinan los parametros marcados de la
	 *            instruccion preparada, su dimension debe ser igual a cuantos ?
	 *            halla en query, si la consulta no necesita parametros su valor
	 *            seria null
	 * @return CachedRowSetImpl
	 */
	public ResultSet getRecordsRset(String strQuery, String parPrepar[],
			Connection conn) throws SQLException {
		ResultSet rst;
		pstmt = getPstmtWithArguments(strQuery, parPrepar, conn);
		rst = pstmt.executeQuery();
		return rst;
	}

	/**
	 * Devuelve la instancia actual del datasource
	 * 
	 * @return
	 */
	public DataSource getDs() {
		return this.ds;
	}
}